package pers.karl.mongodb.common.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author karl
 * @description: 反射工具类
 * @create 2019-06-09 10:11
 */
public class ReflectUtils {

    private static void addParentField(Class clazz, List<Field> fieldList){
        Class superclass = clazz.getSuperclass();
        if(!Object.class.equals(superclass)){
            Field[] superclassDeclaredFields = superclass.getDeclaredFields();
            fieldList.addAll(Arrays.asList(superclassDeclaredFields));
            addParentField(superclass,fieldList);
        }
    }

    private static List<Field> listAllField(Class clazz){
        List<Field> fieldList = new ArrayList<>();

        fieldList.addAll(Arrays.asList(clazz.getDeclaredFields()));

        addParentField(clazz,fieldList);

        return fieldList;
    }

    private static String getMethodName(String fieldName){
        return fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
    }

    private static Method getMethodGet(Class clazz, String fieldName) throws NoSuchMethodException {
        return clazz.getMethod("get" + getMethodName(fieldName));
    }

    /**
     * 只返回同时有public get、set方法的属性
     * @param clazz
     * @return
     */
    public static List<Field> listField(Class clazz){
        List<Field> fieldList = listAllField(clazz);

        List<Field> resultList = new ArrayList<>();
        for (Field field : fieldList) {
            String fieldName = field.getName();
            Class<?> type = field.getType();

            String methodName = getMethodName(fieldName);

            try {

                Method methodGet = clazz.getMethod("get" + methodName);
                if (!Modifier.isPublic(methodGet.getModifiers())) {
                    continue;
                }

                Method methodSet = clazz.getMethod("set" + methodName, type);
                if (!Modifier.isPublic(methodSet.getModifiers())) {
                    continue;
                }

                resultList.add(field);
            } catch (NoSuchMethodException e) {}
        }

        return resultList;
    }

    /**
     * 获取属性值
     * @param entityClass
     * @param entity
     * @param fieldName
     * @param <E>
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static <E> E getBeanValue(Class entityClass, Object entity, String fieldName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method methodGet = getMethodGet(entityClass, fieldName);
        return (E) methodGet.invoke(entity);
    }

}
